﻿
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Access

Imports System.Xml
Imports System.IO
Imports System.Xml.Serialization
Imports System.Runtime.InteropServices

''' <summary>
''' Tranform an access database to SVN sources.  This class should be used to initially create 
''' SVN structure from an access database
''' </summary>
''' <remarks></remarks>
Public Class AccessDBToSVNSources
    Inherits AccessSvnTransformer

    Private Const VERSION_ERR_MSG As String = "The MS Access Version used to export sources ({0}) is different than curent version of access: ({1})"

    Public Property sourceDatabase As String

    Protected Sub tranformDatabaseFile()

        Dim fname As FileInfo = New FileInfo(Me.sourceDatabase)
        Dim dbName As String = AppContext.current.RootSVNPath & "\DB\dbfile"

        If AppContext.current.isNew Then
            AppContext.current.projectInfo.AccessVersion = Me.app.Version
            AppContext.current.projectInfo.AccessBuilt = CStr(Me.app.Build)

        Else
            Dim errmsg As String = String.Format(VERSION_ERR_MSG, _
             AppContext.current.projectInfo.AccessVersion & "." & _
             AppContext.current.projectInfo.AccessBuilt, _
               Me.app.Version & "." & Me.app.Build)

            If Me.app.Version <> AppContext.current.projectInfo.AccessVersion Then
                Throw New ApplicationException(errmsg)

            End If

            If CStr(Me.app.Build) <> AppContext.current.projectInfo.AccessBuilt Then
                Throw New ApplicationException(errmsg)

            End If

        End If

        If Directory.Exists(AppContext.current.RootSVNPath & "\DB") = False Then
            Directory.CreateDirectory(AppContext.current.RootSVNPath & "\DB")
        End If
        If File.Exists(dbName) Then
            File.Delete(dbName)
        End If

        If AppContext.current.isADPProject Then
            Console.WriteLine("Closing Project Connection ")
            Me.app.CurrentProject.CloseConnection()
            ' Call Me.app.CurrentProject.OpenConnection()
        End If


        Me.app.SaveAsText(CType(6, AcObjectType), String.Empty, dbName)
        Console.WriteLine("Exported database to " & dbName)

    End Sub

    ''' <summary>
    ''' Check if access is currently running and has open our database!
    ''' if so, close all forms before saving to disk
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub checkOpenObjects()

        Dim accesApp As Access.Application = Nothing
        Try
            accesApp = AppContext.getRunningAccessComReference()
            If accesApp Is Nothing Then Return
            If accesApp.CurrentDb.Name = AppContext.current.getAccessDatabaseFullName OrElse _
              accesApp.CurrentProject.Name = AppContext.current.getAccessDatabaseFullName Then

                If accesApp.Forms.Count > 0 Or accesApp.Reports.Count > 0 Then

                End If

            End If

        Finally
            If accesApp IsNot Nothing Then
                Marshal.FinalReleaseComObject(accesApp)
            End If
            accesApp = Nothing
        End Try

    End Sub

    Public Overrides Sub Transform()
        Try

            Call raiseTransformStarted()
            Call Me.checkOpenObjects()

            If Me.isCancelled Then
                Console.WriteLine("******* Operation Cancelled **")
                Return
            End If

            If IO.File.Exists(Me.sourceDatabase) = False Then
                Throw New ApplicationException("Source database does not exit")
            End If

            Me.app = New Access.Application
            If AppContext.current.isADPProject Then
                Me.app.OpenAccessProject(Me.sourceDatabase, False)
            Else
                Me.app.OpenCurrentDatabase(Me.sourceDatabase, False)
            End If


            If (AppContext.current.RootSVNPath = app.CurrentProject.Path) Then
                Throw New ApplicationException("base path cannot be the same as the Database path")
            End If

            Me.TransformerProvider = AppContext.getTransformerProvider(Me.sourceDatabase)

            For Each ex As BaseAccessObjectTransformer In Me.Transformers
                ex.App = app
                ex.BaseExportPath = AppContext.current.RootSVNPath
                ex.Save()

                If ex.ObjectList IsNot Nothing AndAlso ex.ObjectList.Count > 0 Then
                    Me.ObjectList.AddRange(ex.ObjectList)
                End If

            Next

            Me.tranformDatabaseFile()

            If Me.isCancelled Then
                Console.WriteLine("******* Operation Cancelled **")
                Return
            End If

            If Me.app.CurrentDb IsNot Nothing Then
                Me.app.CloseCurrentDatabase()
            End If

            Me.writeObjectList()

        Catch e As Exception
            Console.Write("-----------------")
            Console.Write(e.Message)
            Console.Write(e.StackTrace)
            Me.raiseTransformError(e.Message)

        Finally

            Try
                If app IsNot Nothing Then Me.app.Quit()

            Catch ignore As Exception
                Console.WriteLine("Error trying to quit access:" & ignore.Message)
            End Try

            GC.Collect()
            GC.WaitForPendingFinalizers()

            If app IsNot Nothing Then Marshal.ReleaseComObject(app)
            app = Nothing

            Call raiseTransformEnd()

        End Try

    End Sub

    Private Sub writeObjectList()

        Dim writer As XmlTextWriter = Nothing
        Try
            writer = New XmlTextWriter(AppContext.current.RootSVNPath & "\ObjectList.xml", _
                     System.Text.Encoding.UTF8)

            writer.Formatting = Formatting.Indented
            writer.WriteStartDocument()

            writer.WriteStartElement("DatabaseObjects")

            For Each ref As IExportedAccessObject In Me.ObjectList

                writer.WriteStartElement("DatabaseObject")
                writer.WriteElementString("Name", ref.Name)
                writer.WriteElementString("Type", CStr(CInt(ref.type)))
                writer.WriteEndElement()

            Next ref

            writer.WriteEndDocument()

        Finally
            writer.Close()

        End Try

    End Sub



End Class
